package com.xinyue.game.gateway.local;

import com.alibaba.fastjson.JSONObject;
import com.xinyue.game.gateway.common.*;
import com.xinyue.game.jwt.GameJwtService;
import com.xinyue.game.jwt.GameRoleToken;
import com.xinyue.game.jwt.JwtTokenErrorException;
import com.xinyue.game.jwt.JwtTokenExpiredException;
import com.xinyue.game.message.GameServerMessageModel;
import com.xinyue.game.utils.ByteBufUtil;
import com.xinyue.game.utils.GameServerUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class GameChannelConfirmHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(GameChannelConfirmHandler.class);
    @Autowired
    private GameGatewayConfig gameGatewayConfig;
    @Autowired
    private UserChannelService userChannelService;
    private static GameJwtService gameJwtService = new GameJwtService();

    private Future<?> future;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String channelId = GameServerUtil.getChannelId(ctx.channel());
        logger.info("连接成功,等待连接认证...，channelId: {}", channelId);
        // 添加一个延时任务，过一段时间之后，判断是否认证成功，如果认证成功了，gameChannel一定不会为空
        future = ctx.channel().eventLoop().schedule(() -> {
            String playerId = userChannelService.getPlayerId(ctx);
            if (playerId == null) {
                logger.warn("连接未认证成功，主动断开连接，channelId:{}", channelId);
                ctx.close();
            } else {
                logger.info("连接认证成功!!,playerId: {},channelId: {}", playerId, channelId);
            }
        }, gameGatewayConfig.getConfirmTimeout(), TimeUnit.SECONDS);
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (future != null && future.isCancellable()) {
            logger.debug("连被关闭，取消连接通道认证的延迟任务,channelId:{}", GameServerUtil.getChannelId(ctx.channel()));
            future.cancel(true);
        }
        ctx.fireChannelInactive();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof GameServerMessageModel) {
            GameServerMessageModel<GameGatewayMessageRequestHeader> gatewayMessageWrapper = (GameServerMessageModel) msg;
            GameGatewayMessageRequestHeader header = gatewayMessageWrapper.getHeader();
            if (HandleMessageID.CONFIRM_CHANNEL_URI.equals(header.getRequestUri())) {
                // 处理认证业务
                try {
                    String body = ByteBufUtil.readLeftString(gatewayMessageWrapper.getBody());
                    String token = this.getToken(body);
                    GameServerMessageModel<GameGatewayMessageResponseHeader> response;
                    if (token == null) {
                        response = GatewayResponseUtil.getResponseMessageModel(gatewayMessageWrapper, ServerErrorCode.AUTH_ERROR, "令牌不能为空");
                        ctx.writeAndFlush(response).addListener(future1 -> {
                            ctx.close();
                        });
                    } else {
                        byte[] key = gameGatewayConfig.getTokenAesKey().getBytes(StandardCharsets.UTF_8);
                        try {
                            GameRoleToken gameRoleToken = gameJwtService.checkTokenAndGet(token, key, GameRoleToken.class);
                            userChannelService.addChannelCache(gameRoleToken.getPlayerId(), ctx);
                            response = GatewayResponseUtil.getResponseMessageModel(gatewayMessageWrapper, 0, null);
                            ctx.writeAndFlush(response);
                            if (this.future != null && this.future.isCancellable()) {
                                this.future.cancel(true);
                            }
                            logger.info("连接认证成功，channelId: {}", GameServerUtil.getChannelId(ctx.channel()));
                        } catch (JwtTokenErrorException | JwtTokenExpiredException exception) {
                            logger.error("token验证失败", exception);
                            response = GatewayResponseUtil.getResponseMessageModel(gatewayMessageWrapper, ServerErrorCode.AUTH_ERROR, "登陆状态已失效，请重新登陆");
                            ctx.writeAndFlush(response).addListener(future1 -> {
                                ctx.close();
                            });
                        }
                    }
                } catch (Throwable e) {
                    logger.error("连接认证处理异常", e);
                }
            } else {
                ctx.fireChannelRead(msg);
            }
        } else {
            ctx.fireChannelRead(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("服务器异常", cause);
    }

    private String getToken(String body) {
        JSONObject data = JSONObject.parseObject(body);
        return data.getString("token");
    }
}
